package com.mojian.service.impl;

import com.mojian.service.RecommendationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 推荐系统服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RecommendationServiceImpl implements RecommendationService {

    private final JdbcTemplate jdbcTemplate;

    @Override
    public Map<String, Object> getPersonalizedRecommendations(Long userId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 1. 获取用户最常浏览的标签
            List<Map<String, Object>> userFavoriteTags = getUserFavoriteTags(userId);
            
            // 2. 获取用户最常浏览的分类
            List<Map<String, Object>> userFavoriteCategories = getUserFavoriteCategories(userId);
            
            // 3. 基于标签的推荐
            List<Map<String, Object>> tagBasedRecommendations = getTagBasedRecommendations(userId, userFavoriteTags);
            
            // 4. 基于分类的推荐
            List<Map<String, Object>> categoryBasedRecommendations = getCategoryBasedRecommendations(userId, userFavoriteCategories);
            
            // 5. 基于浏览时长的推荐
            List<Map<String, Object>> timeBasedRecommendations = getTimeBasedRecommendations(userId);
            
            // 6. 合并推荐结果，去重
            Set<Long> recommendedArticleIds = new HashSet<>();
            List<Map<String, Object>> finalRecommendations = new ArrayList<>();
            
            // 添加基于标签的推荐（优先级最高）
            addUniqueRecommendations(tagBasedRecommendations, finalRecommendations, recommendedArticleIds, 5);
            
            // 添加基于分类的推荐（优先级次之）
            addUniqueRecommendations(categoryBasedRecommendations, finalRecommendations, recommendedArticleIds, 5);
            
            // 添加基于时长的推荐（优先级最低）
            addUniqueRecommendations(timeBasedRecommendations, finalRecommendations, recommendedArticleIds, 5);
            
            // 如果推荐数量不足，添加热门文章补充
            if (finalRecommendations.size() < 10) {
                List<Map<String, Object>> popularArticles = getPopularArticles();
                addUniqueRecommendations(popularArticles, finalRecommendations, recommendedArticleIds, 10 - finalRecommendations.size());
            }
            
            result.put("recommendations", finalRecommendations);
            result.put("favoriteTags", userFavoriteTags.stream().limit(5).collect(Collectors.toList()));
            result.put("favoriteCategories", userFavoriteCategories.stream().limit(3).collect(Collectors.toList()));
            
        } catch (Exception e) {
            log.error("生成个性化推荐失败", e);
            // 如果出错，返回热门文章作为备选
            result.put("recommendations", getPopularArticles());
            result.put("isBackup", true);
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> getUserBrowsingAnalysis(Long userId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 1. 用户浏览文章总数
            Integer totalViews = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM sys_user_article_view WHERE user_id = ?", 
                Integer.class, 
                userId
            );
            
            // 2. 用户最常浏览的标签
            List<Map<String, Object>> favoriteTags = getUserFavoriteTags(userId);
            
            // 3. 用户最常浏览的分类
            List<Map<String, Object>> favoriteCategories = getUserFavoriteCategories(userId);
            
            // 4. 用户浏览时长分析
            Map<String, Object> timeAnalysis = getUserTimeAnalysis(userId);
            
            // 5. 用户浏览趋势（按天统计）
            List<Map<String, Object>> viewTrends = getUserViewTrends(userId);
            
            result.put("totalViews", totalViews);
            result.put("favoriteTags", favoriteTags);
            result.put("favoriteCategories", favoriteCategories);
            result.put("timeAnalysis", timeAnalysis);
            result.put("viewTrends", viewTrends);
            
        } catch (Exception e) {
            log.error("生成用户浏览分析失败", e);
            result.put("error", "生成用户浏览分析失败");
        }
        
        return result;
    }
    
    /**
     * 获取用户最喜欢的标签（按浏览次数排序）
     */
    private List<Map<String, Object>> getUserFavoriteTags(Long userId) {
        String sql = "SELECT t.id, t.name, COUNT(*) as count " +
                    "FROM sys_user_article_tag uat " +
                    "JOIN sys_tag t ON uat.tag_id = t.id " +
                    "WHERE uat.user_id = ? " +
                    "GROUP BY t.id, t.name " +
                    "ORDER BY count DESC";
        
        return jdbcTemplate.queryForList(sql, userId);
    }
    
    /**
     * 获取用户最喜欢的分类（按浏览次数排序）
     */
    private List<Map<String, Object>> getUserFavoriteCategories(Long userId) {
        String sql = "SELECT c.id, c.name, COUNT(*) as count " +
                    "FROM sys_user_article_view uav " +
                    "JOIN sys_category c ON uav.category_id = c.id " +
                    "WHERE uav.user_id = ? " +
                    "GROUP BY c.id, c.name " +
                    "ORDER BY count DESC";
        
        return jdbcTemplate.queryForList(sql, userId);
    }
    
    /**
     * 基于标签的文章推荐
     */
    private List<Map<String, Object>> getTagBasedRecommendations(Long userId, List<Map<String, Object>> favoriteTags) {
        if (favoriteTags.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 提取用户最喜欢的前3个标签ID
        List<Integer> topTagIds = favoriteTags.stream()
                .limit(3)
                .map(tag -> Integer.parseInt(tag.get("id").toString()))
                .collect(Collectors.toList());
        
        if (topTagIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 构建IN查询的参数
        String inSql = String.join(",", Collections.nCopies(topTagIds.size(), "?"));
        
        // 查询包含这些标签的、用户未浏览过的文章
        String sql = "SELECT a.id, a.title, a.summary, a.cover, a.create_time as createTime, c.name as categoryName " +
                    "FROM sys_article a " +
                    "JOIN sys_article_tag at ON a.id = at.article_id " +
                    "JOIN sys_category c ON a.category_id = c.id " +
                    "WHERE at.tag_id IN (" + inSql + ") " +
                    "AND a.status = 1 " +
                    "AND a.id NOT IN (SELECT DISTINCT article_id FROM sys_user_article_view WHERE user_id = ?) " +
                    "ORDER BY a.create_time DESC " +
                    "LIMIT 10";
        
        // 构建参数数组
        Object[] params = new Object[topTagIds.size() + 1];
        for (int i = 0; i < topTagIds.size(); i++) {
            params[i] = topTagIds.get(i);
        }
        params[topTagIds.size()] = userId;
        
        return jdbcTemplate.queryForList(sql, params);
    }
    
    /**
     * 基于分类的文章推荐
     */
    private List<Map<String, Object>> getCategoryBasedRecommendations(Long userId, List<Map<String, Object>> favoriteCategories) {
        if (favoriteCategories.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 提取用户最喜欢的前2个分类ID
        List<Integer> topCategoryIds = favoriteCategories.stream()
                .limit(2)
                .map(category -> Integer.parseInt(category.get("id").toString()))
                .collect(Collectors.toList());
        
        if (topCategoryIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 构建IN查询的参数
        String inSql = String.join(",", Collections.nCopies(topCategoryIds.size(), "?"));
        
        // 查询这些分类下的、用户未浏览过的文章
        String sql = "SELECT a.id, a.title, a.summary, a.cover, a.create_time as createTime, c.name as categoryName " +
                    "FROM sys_article a " +
                    "JOIN sys_category c ON a.category_id = c.id " +
                    "WHERE a.category_id IN (" + inSql + ") " +
                    "AND a.status = 1 " +
                    "AND a.id NOT IN (SELECT DISTINCT article_id FROM sys_user_article_view WHERE user_id = ?) " +
                    "ORDER BY a.create_time DESC " +
                    "LIMIT 10";
        
        // 构建参数数组
        Object[] params = new Object[topCategoryIds.size() + 1];
        for (int i = 0; i < topCategoryIds.size(); i++) {
            params[i] = topCategoryIds.get(i);
        }
        params[topCategoryIds.size()] = userId;
        
        return jdbcTemplate.queryForList(sql, params);
    }
    
    /**
     * 基于浏览时长的文章推荐
     */
    private List<Map<String, Object>> getTimeBasedRecommendations(Long userId) {
        // 查询用户浏览时长最长的文章，并推荐相似文章
        String sql = "SELECT a.id, a.title, a.summary, a.cover, a.create_time as createTime, c.name as categoryName " +
                    "FROM sys_article a " +
                    "JOIN sys_category c ON a.category_id = c.id " +
                    "WHERE a.category_id IN (SELECT category_id FROM sys_user_article_view WHERE user_id = ? GROUP BY category_id ORDER BY SUM(read_time) DESC LIMIT 1) " +
                    "AND a.status = 1 " +
                    "AND a.id NOT IN (SELECT DISTINCT article_id FROM sys_user_article_view WHERE user_id = ?) " +
                    "ORDER BY a.view_count DESC " +
                    "LIMIT 5";
        
        return jdbcTemplate.queryForList(sql, userId, userId);
    }
    
    /**
     * 获取热门文章（作为备选推荐）
     */
    private List<Map<String, Object>> getPopularArticles() {
        String sql = "SELECT a.id, a.title, a.summary, a.cover, a.create_time as createTime, c.name as categoryName " +
                    "FROM sys_article a " +
                    "JOIN sys_category c ON a.category_id = c.id " +
                    "WHERE a.status = 1 " +
                    "ORDER BY a.view_count DESC " +
                    "LIMIT 10";
        
        return jdbcTemplate.queryForList(sql);
    }
    
    /**
     * 添加唯一的推荐到最终列表
     */
    private void addUniqueRecommendations(List<Map<String, Object>> source, List<Map<String, Object>> target, 
                                         Set<Long> existingIds, int maxToAdd) {
        int added = 0;
        for (Map<String, Object> article : source) {
            Long articleId = Long.parseLong(article.get("id").toString());
            if (!existingIds.contains(articleId) && added < maxToAdd) {
                target.add(article);
                existingIds.add(articleId);
                added++;
            }
            
            if (added >= maxToAdd) {
                break;
            }
        }
    }
    
    /**
     * 获取用户浏览时长分析
     */
    private Map<String, Object> getUserTimeAnalysis(Long userId) {
        Map<String, Object> result = new HashMap<>();
        
        // 总浏览时长
        Integer totalReadTime = jdbcTemplate.queryForObject(
            "SELECT SUM(read_time) FROM sys_user_article_view WHERE user_id = ?", 
            Integer.class, 
            userId
        );
        
        // 平均浏览时长
        Double avgReadTime = jdbcTemplate.queryForObject(
            "SELECT AVG(read_time) FROM sys_user_article_view WHERE user_id = ?", 
            Double.class, 
            userId
        );
        
        // 最长浏览时长
        Integer maxReadTime = jdbcTemplate.queryForObject(
            "SELECT MAX(read_time) FROM sys_user_article_view WHERE user_id = ?", 
            Integer.class, 
            userId
        );
        
        result.put("totalReadTime", totalReadTime != null ? totalReadTime : 0);
        result.put("avgReadTime", avgReadTime != null ? avgReadTime : 0);
        result.put("maxReadTime", maxReadTime != null ? maxReadTime : 0);
        
        return result;
    }
    
    /**
     * 获取用户浏览趋势（按天统计）
     */
    private List<Map<String, Object>> getUserViewTrends(Long userId) {
        String sql = "SELECT DATE(create_time) as date, COUNT(*) as count " +
                    "FROM sys_user_article_view " +
                    "WHERE user_id = ? " +
                    "GROUP BY DATE(create_time) " +
                    "ORDER BY date DESC " +
                    "LIMIT 7";
        
        return jdbcTemplate.queryForList(sql, userId);
    }
} 